package com.zt.teacher.service.impl;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.google.common.collect.Lists;
import com.zt.common.Do.ClassWithTeachDO;
import com.zt.common.common.ApiException;
import com.zt.common.common.CodeMsg;
import com.zt.common.pojo.ActiveClass;
import com.zt.common.pojo.exam.Exam;
import com.zt.common.pojo.exam.ExamAnswer;
import com.zt.common.pojo.exam.ExamQuestionBank;
import com.zt.common.pojo.homework.Homework;
import com.zt.common.pojo.homework.HomeworkAnswer;
import com.zt.common.utils.ClassUtil;
import com.zt.common.utils.JwtUtil;
import com.zt.common.utils.RedisUtil;
import com.zt.teacher.dao.ActiveClassAssociationDao;
import com.zt.teacher.dao.ActiveClassDao;
import com.zt.teacher.dto.ActiveClassDTO;
import com.zt.teacher.dto.ClassTimeDTO;
import com.zt.teacher.dto.ScoreDTO;
import com.zt.teacher.dto.StuScoreSummaryDTO;
import com.zt.teacher.netty.MyTextWebSocketFrameHandler;
import com.zt.teacher.service.*;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * description:
 * author:zt
 * date:2021-12-16
 */
@Service
@Transactional
public class ActiveClassServiceImpl implements ActiveClassService {

    private static final Log log = LogFactory.get();

    @Autowired
    private ActiveClassDao activeClassDao;
    @Autowired
    private ClassSelectionService classSelectionService;
    @Autowired
    private ActiveClassAssociationDao activeClassAssociationDao;
    @Autowired
    private CourseService courseService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MyTextWebSocketFrameHandler handler;
    @Autowired
    private ExamService examService;
    @Autowired
    private HomeworkService homeworkService;
    @Autowired
    private SignInService signInService;

    /**
     * @param activeClassDTO 开设课堂activeClass 与 与之关联的originClass学校班级数组
     * @param request 获取当前登录老师
     */
    @Override
    public void insert(ActiveClassDTO activeClassDTO, HttpServletRequest request) {
        ActiveClass activeClass = activeClassDTO.getActiveClass();
        log.info("activeClass：" + activeClass);
        List<Integer> originClassIds = activeClassDTO.getOriginClassIdList();
        log.info("originClassIds：" + originClassIds);
        String semester = activeClass.getSemester();

        boolean compulsory = courseService.isCompulsory(activeClass.getCourseId());
        //如果是必修课 那么需要判断当前要开的activeClass的上课时间是否会与 学校班级的必修课上课时间冲突
        if(compulsory) {
            String classTimeByOriginClassId = getClassTimeByOriginClassId(new ClassTimeDTO(originClassIds, semester));
            String classTimeByTeacherId = getClassTimeByTeacherId(semester, request);
            if (ClassUtil.isTimeConflict(classTimeByOriginClassId,activeClass.getClassTime()) ||
                    ClassUtil.isTimeConflict(classTimeByTeacherId,activeClass.getClassTime())) {
                throw new ApiException(CodeMsg.START_CLASS_TIME_CONFLICT);
            }
        }

        if (!redisUtil.hasKey(semester+"-startClass"))
           throw new ApiException(CodeMsg.NOT_START_CLASS);

        if (activeClass.getCourseId() == 0)
            throw new ApiException(CodeMsg.BODY_NOT_MATCH);

        //设置开课老师id 为 当前登录老师id
        String token = request.getHeader("Authorization");
        String teacherId = JwtUtil.decodedGetID(token);
        log.info("开课老师id：" + teacherId);
        activeClass.setTeacherId(teacherId);

        //新增一条课堂记录
        activeClassDao.insert(activeClass);

        //关联课堂与原始班级
        activeClassAssociationDao.insertMulti(activeClass.getId(),originClassIds);

        //若该课堂对应的课程为必修课，则为原始班级的学生自动选上
        if (compulsory) {
            classSelectionService.insertCompulsory(activeClass, originClassIds);
        }

        //在服务器下为班级创建文件夹 以后存放班级资源
        File file = new File("/root/resources/" + activeClass.getId() + "/");
        file.mkdirs();
    }

    @Override
    public void update(ActiveClass activeClass){
        activeClassDao.update(activeClass);
    }

    @Override
    public List<ActiveClass> getClassByTeacherId(String semester, HttpServletRequest request) {
        String token = request.getHeader("authorization");
        String teacherId = JwtUtil.decodedGetID(token);
        return activeClassDao.getClassByTeacherIdAndSemester(semester,teacherId);
    }

    /**
     * @param classTimeDTO originClass学校班级数组 与 开课学期semester
     * @return 这些班级在该学期的所有必修课上课时间
     */
    @Override
    public String getClassTimeByOriginClassId(ClassTimeDTO classTimeDTO) {
        List<Integer> originClassIdList = classTimeDTO.getOriginClassIdList();
        String semester = classTimeDTO.getSemester();

        List<ActiveClass> activeClasses = activeClassDao.getClassByOriginClassId(semester, originClassIdList);

        return ClassUtil.getClassTime(activeClasses);
    }

    @Override
    public String getClassTimeByTeacherId(String semester,HttpServletRequest request) {
        String token = request.getHeader("authorization");
        String teacherId = JwtUtil.decodedGetID(token);

        List<ActiveClass> activeClasses = activeClassDao.getClassByTeacherIdAndSemester(semester,teacherId);

        return ClassUtil.getClassTime(activeClasses);
    }

    @Override
    public List<ActiveClass> getElectiveClassBySemester(String semester) {
        return activeClassDao.getElectiveClassBySemester(semester);
    }

    /**
     * 开启上课 加入ws group
     * @param classId 班级id
     */
    @Override
    public void attendClass(int classId, HttpServletRequest request) {
        ActiveClass activeClass = activeClassDao.getClassById(classId);
        if (activeClass == null)
            throw new ApiException(CodeMsg.CLASS_NOT_EXISTED);

        //获取要开的这节课所在学期的该老师的所有课堂
        String semester = activeClassDao.getClassById(classId).getSemester();
        List<ActiveClass> classes = getClassByTeacherId(semester, request);
        classes.forEach(c -> {
            if (c.getId()!=classId){
                if (handler.isHavingClass(c.getId()))
                    throw new ApiException(CodeMsg.HAVE_CLASS_ON);
            }
        });

        handler.attendClass(classId);
        //课堂最多开启三个小时
        redisUtil.set(classId + "正在上课",1,60 * 60 * 3);
    }

    @Override
    public List<ActiveClass> getTeacherCurrentClass(String semester, HttpServletRequest request){
        List<ActiveClass> classes = getClassByTeacherId(semester, request);
        List<ActiveClass> res = new ArrayList<>();
        classes.forEach(c -> {
            if (handler.isHavingClass(c.getId())) res.add(c);
        });
        return res;
    }

    /**
     * @param semester 学期
     * @param request 获取学生id
     * @return 获取学生正在上课的课堂
     */
    @Override
    public List<ClassWithTeachDO> getStudentCurrentClass(String semester, HttpServletRequest request){
        String studentId = JwtUtil.decodedGetID(request.getHeader("authorization"));

        List<ClassWithTeachDO> classes = activeClassDao.getStudentSelectedClass(studentId,semester);
        List<ClassWithTeachDO> res = new ArrayList<>();
        classes.forEach(c -> {
            if (handler.isHavingClass(c.getId())) res.add(c);
        });
        return res;
    }

    @Override
    public String uploadResources(MultipartFile file,int classId) throws IOException {
        if (file==null) throw new ApiException(CodeMsg.RESOURCE_FORMAT_NOT_MATCH);
        //允许上传的文件后缀名
        List<String> list = Lists.newArrayList("pptx","jpg","jpeg","png","gif","doc","docx","pdf","md","txt","ppt","xlsx","xls","zip","rar");

        String fileName = file.getOriginalFilename();
        log.info(fileName);

        String extendName = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        log.info(extendName);
        if (!list.contains(extendName)) throw new ApiException(CodeMsg.RESOURCE_FORMAT_NOT_MATCH);

        String filePath = "/root/resources/" + classId + "/";
        //若路径不存在则表示班级未创建
        if (!new File(filePath).exists()) {
            throw new ApiException(CodeMsg.CLASS_NOT_EXISTED);
        }

        String realName = System.currentTimeMillis() + "-" + fileName;
        File file1 = new File(filePath,realName);
        file.transferTo(file1);

        if (handler.isHavingClass(classId))  handler.remindStudents(classId);
        return realName;
    }

    @Override
    public void deleteResources(int classId,String fileName) {
        File file = new File("/root/resources/" + classId + "/" + fileName);
        if (file.exists()) file.delete();
        else
            throw new ApiException(CodeMsg.RESOURCE_NOT_EXISTED);
    }

    @Override
    public List<ActiveClass> getClassByTeaAndStuId(HttpServletRequest request,String studentId, String semester){
        String teacherId = JwtUtil.decodedGetID(request.getHeader("Authorization"));

        return activeClassDao.getClassByTeaAndStuId(teacherId,studentId,semester);
    }

    @Override
    public ActiveClass getClassById(int classId) {
        return activeClassDao.getClassById(classId);
    }

    /**
     * @param classId 班级id
     * @return 获取该班级所有学生所有考试、作业得分情况以及签到次数
     */
    @Override
    public ArrayList<StuScoreSummaryDTO> getSummaryByClassId(HttpServletRequest request, int classId){
        ArrayList<StuScoreSummaryDTO> res = new ArrayList<>();

        //获取该班级所有考试
        List<Exam> examList = examService.getExamByClassId(classId);
        //获取该班级所有作业
        List<Homework> homeworkList = homeworkService.getByClassId(request, classId);
        //获取该班级所有签到id
        List<Integer> signInList = signInService.getSignInByClassId(classId);
        //获取该班级所有学生id
        List<String> studentIdList = classSelectionService.getStuIdByClassId(classId);

        for (String studentId : studentIdList) {
            StuScoreSummaryDTO summaryDTO = new StuScoreSummaryDTO();
            ArrayList<ScoreDTO> examsScore = new ArrayList<>();
            ArrayList<ScoreDTO> homeworksScore = new ArrayList<>();
            summaryDTO.setExamsScore(examsScore).setHomeworksScore(homeworksScore);

            examList.forEach(e -> {
                double score = examService.getScore(studentId, e.getId());
                examsScore.add(new ScoreDTO(e.getId(),score));
            });

            homeworkList.forEach(h ->{
                HomeworkAnswer answer = homeworkService.getScoreByStuId(studentId, h.getId());
                if (answer!=null)
                    homeworksScore.add(new ScoreDTO(h.getId(),answer.getPoint()));
            });

            if (signInList.size()!=0) {
                int signInTime = signInService.getSignInTime(signInList, studentId);
                summaryDTO.setSignInTime(signInTime).setStudentId(studentId);
            }

            res.add(summaryDTO);
        }
        return res;
    }
}
